package pl.vanta.mjuzik2.impl.player;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;

import pl.vanta.mjuzik2.api.AudioFile;
import pl.vanta.mjuzik2.api.listeners.PlayerEventListener;
import pl.vanta.mjuzik2.api.listeners.PlayerProgressListener;
import pl.vanta.mjuzik2.api.services.PlayerService;
import pl.vanta.mjuzik2.impl.player.engine.BasicController;
import pl.vanta.mjuzik2.impl.player.engine.BasicPlayer;
import pl.vanta.mjuzik2.impl.player.engine.BasicPlayerEvent;
import pl.vanta.mjuzik2.impl.player.engine.BasicPlayerException;
import pl.vanta.mjuzik2.impl.player.engine.BasicPlayerListener;

public class BasicPlayerServiceImpl implements PlayerService
{
	private final BasicPlayer					player;

	AudioFile									currentFile;
	int											currentFileLength;

	private Collection<PlayerEventListener>		eventListeners;
	private Collection<PlayerProgressListener>	progressListeners;

	public BasicPlayerServiceImpl()
	{
		this.player = new BasicPlayer();
		this.player.addBasicPlayerListener(new BasicPlayerListenerImpl());

		this.eventListeners = new ArrayList<PlayerEventListener>();
		this.progressListeners = new ArrayList<PlayerProgressListener>();
	}

	@Override
	public void pause()
	{
		if (this.player.getStatus() == PlayerStatus.PLAYING)
		{
			this.player.pause();
		}
		else if (this.player.getStatus() == PlayerStatus.PAUSED)
		{
			this.player.resume();
		}
	}

	@Override
	public void stop()
	{
		this.player.stop();
	}

	@Override
	public void play(AudioFile audioFile)
	{
		if (this.player.getStatus() == PlayerStatus.PLAYING || this.player.getStatus() == PlayerStatus.PAUSED)
		{
			this.player.stop();
		}

		this.currentFile = audioFile;

		try
		{
			this.player.open(this.currentFile.getFile());
			this.player.play();

			// this.player.setGain(this.controllerPanel.getVolume());
			// this.player.setPan(this.controllerPanel.getBalance());

		}
		catch (BasicPlayerException e)
		{
		}
	}

	@Override
	public void setVolume(double value)
	{
		try
		{
			this.player.setGain(value);
		}
		catch (BasicPlayerException e)
		{
		}
	}

	@Override
	public void setBalance(double value)
	{
		try
		{
			this.player.setPan(value);
		}
		catch (BasicPlayerException e)
		{
		}
	}

	float calculatePercent(int bytes)
	{
		return bytes * 100f / this.currentFileLength;
	}

	@Override
	public void addPlayerEventListener(PlayerEventListener pel)
	{
		this.eventListeners.add(pel);
	}

	@Override
	public void removePlayerEventListener(PlayerEventListener pel)
	{
		this.eventListeners.remove(pel);
	}

	public void addPlayerProgressListener(PlayerProgressListener listener)
	{
		this.progressListeners.add(listener);
	}

	public void removePlayerProgressListener(PlayerProgressListener listener)
	{
		this.progressListeners.remove(listener);
	}

	void firePlayerStoppedListeners()
	{
		for (PlayerEventListener listener : this.eventListeners)
		{
			listener.stopped();
		}
	}

	void firePlayerStartedListeners()
	{
		for (PlayerEventListener listener : this.eventListeners)
		{
			listener.started();
		}
	}

	void firePlayerPausedListeners(int position)
	{
		for (PlayerEventListener listener : this.eventListeners)
		{
			listener.paused(position);
		}
	}

	void firePlayerOpenedListeners(AudioFile audioFile)
	{
		for (PlayerEventListener listener : this.eventListeners)
		{
			listener.opened(audioFile);
		}
	}

	void firePlayerProgressListeners(long time, float percent, int bytes)
	{
		for (PlayerProgressListener listener : this.progressListeners)
		{
			listener.updateProgress(time, percent, bytes);
		}
	}

	class BasicPlayerListenerImpl implements BasicPlayerListener
	{
		@Override
		public void opened(Object stream, Map<String, Object> properties)
		{
			BasicPlayerServiceImpl.this.currentFileLength = (Integer) BasicPlayerServiceImpl.this.currentFile
					.getFileInfo().getProperties().get("audio.length.bytes");
		}

		@Override
		public void progress(int bytesread, long microseconds, byte[] pcmdata, Map<String, Object> properties)
		{
			float progress = 1.0f * bytesread / BasicPlayerServiceImpl.this.currentFileLength;
			float percent = calculatePercent(bytesread);

			long milis = Math.round(progress * BasicPlayerServiceImpl.this.currentFile.getFileInfo().getPlayTime());

			firePlayerProgressListeners(milis, percent, bytesread);
		}

		@Override
		public void setController(BasicController controller)
		{
		}

		@Override
		public void stateUpdated(BasicPlayerEvent event)
		{
			switch (event.getEvent())
			{
				case STOPPED:
					playerStoppped(event.getPosition());
					break;

				case EOM:
					playerStoppped(BasicPlayerServiceImpl.this.currentFileLength);
					break;

				case PAUSED:
					firePlayerPausedListeners(event.getPosition());
					break;

				case OPENED:
					playerOpened(BasicPlayerServiceImpl.this.currentFile);
					break;

				case PLAYING:
					firePlayerStartedListeners();
					break;

				case RESUMED:
					firePlayerStartedListeners();
					break;

				default:
					break;
			}
		}

		private void playerStoppped(int bytes)
		{
			if (bytes == -1)
			{
				bytes = BasicPlayerServiceImpl.this.currentFileLength;
			}

			firePlayerStoppedListeners();
		}

		private void playerOpened(AudioFile audioFile)
		{
			BasicPlayerServiceImpl.this.currentFileLength = (Integer) BasicPlayerServiceImpl.this.currentFile
					.getFileInfo().getProperties().get("audio.length.bytes");

			firePlayerOpenedListeners(audioFile);
		}
	}
}